<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Chapter&nbsp;10.&nbsp;上下文（Context）</title>
    <link rel="stylesheet" href="css/html.css" type="text/css">
    <meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
    <link rel="home" href="index.html" title="JBoss jBPM 3.1">
    <link rel="up" href="index.html" title="JBoss jBPM 3.1">
    <link rel="previous" href="processmodelling.html" title="Chapter&nbsp;9.&nbsp;Process Modelling">
    <link rel="next" href="taskmanagement.html" title="Chapter&nbsp;11.&nbsp;Task management">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
    <table width="100%" summary="Navigation header">
        <tr>
            <th colspan="3" align="center">Chapter&nbsp;10.&nbsp;上下文（Context）</th>
        </tr>
        <tr>
            <td width="20%" align="left"><a accesskey="p" href="processmodelling.html">Prev</a>&nbsp;</td>
            <th width="60%" align="center">&nbsp;</th>
            <td width="20%" align="right">&nbsp;<a accesskey="n" href="taskmanagement.html">Next</a></td>
        </tr>
    </table>
    <hr>
</div>
<div class="chapter" lang="cn">
<div class="titlepage">
    <div>
        <div><h2 class="title"><a name="context"></a>Chapter&nbsp;10.&nbsp;上下文（Context）</h2></div>
    </div>
    <div></div>
</div>
<p>Context is about process variables. Process variables are
    key-value pairs that maintain information related to the process instance.
    Since the context must be storable in a database, some minor limitations
    apply.</p>

<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="accessingvariables"></a>10.1.&nbsp;访问变量
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>org.jbpm.context.exe.ContextInstance serves as the central
        interface to work with process variables. You can obtain the
        ContextInstance from a ProcessInstance like this : </p><pre class="programlisting">ProcessInstance processInstance = ...;
ContextInstance contextInstance = (ContextInstance) processInstance.getInstance(ContextInstance.class);</pre>
    <p>The most basic operations are</p><pre class="programlisting">void ContextInstance.setVariable(String variableName, Object value);
void ContextInstance.setVariable(String variableName, Object value, Token token);
Object ContextInstance.getVariable(String variableName);
Object ContextInstance.getVariable(String variableName, Token token);</pre>
    <p>The variable names are java.lang.String. By default, jBPM supports the following
        value types:
    </p>

    <p>
    </p>

    <div class="itemizedlist">
        <ul type="disc">
            <li><tt class="literal">java.lang.String</tt></li>
            <li><tt class="literal">java.lang.Boolean</tt></li>
            <li><tt class="literal">java.lang.Character</tt></li>
            <li><tt class="literal">java.lang.Float</tt></li>
            <li><tt class="literal">java.lang.Double</tt></li>
            <li><tt class="literal">java.lang.Long</tt></li>
            <li><tt class="literal">java.lang.Byte</tt></li>
            <li><tt class="literal">java.lang.Short</tt></li>
            <li><tt class="literal">java.lang.Integer</tt></li>
            <li><tt class="literal">java.util.Date</tt></li>
            <li><tt class="literal">byte[]</tt></li>
            <li><tt class="literal">java.io.Serializable</tt></li>
            <li><tt class="literal">classes that are persistable with hibernate</tt></li>
        </ul>
    </div>
    <p>
    </p>

    <p>Also an untyped null value can be stored persistently.
    </p>

    <p>All other types can be stored in the process variables without any problem. But
        it will cause an exception when you try to save the process instance.
    </p>

    <p>To configure jBPM for storing hibernate persistent objects in the variables,
        see Storing hibernate persistent objects.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="variablelifetime"></a>10.2.&nbsp;变量的生命周期</h2>
            </div>
        </div>
        <div></div>
    </div>
    <p>Variables do not have to be declared in the process archive. At runtime, you
        can just put any java object in the variables. If that variable was not present, it will
        be created. Just the same as with a plain <tt class="literal">java.util.Map</tt>.</p>

    <p>Variables can be deleted with</p><pre class="programlisting">ContextInstance.deleteVariable(String variableName);
ContextInstance.deleteVariable(String variableName, Token token);</pre>
    <p>Automatic changing of types is now supported. This means that it is allowed to
        overwrite a variable with a value of a different type. Of course, you should try to
        limit the number of type changes since this creates a more db communication then a
        plain update of a column.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="variablepersistence"></a>10.3.&nbsp;变量的持久化
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>The variables are a part of the process instance. Saving the process instance
        in the database, brings the database in sync with the process instance. The variables
        are created, updated and deleted from the database as a result of saving (=updating)
        the process instance in the database. For more information, see
        <a href="persistence.html" title="Chapter&nbsp;7.&nbsp;Persistence">Chapter&nbsp;7, <i>Persistence</i></a>.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="variablescopes"></a>10.4.&nbsp;变量的范围</h2>
            </div>
        </div>
        <div></div>
    </div>
    <p>Each path of execution (read: token) has its own set of process variables.
        Requesting a variable is always done on a token. Process instances have a tree
        of tokens (see <a href="graphorientedprogramming.html" title="Chapter&nbsp;4.&nbsp;Graph Oriented Programming">graph
        oriented programming</a>).
        When requesting a variable without specifying a token, the default token is the
        root token.
    </p>

    <p>The variable lookup is done recursively over the parents of the given
        token. The behaviour is similar to the scoping of variables in programming
        languages.
    </p>

    <p>When a non-existing variable is set on a token, the variable is created
        on the root-token. This means that each variable has by default process
        scope. To make a variable token-local, you have to create it explicitely
        with:</p>
    <pre class="programlisting">ContextInstance.createVariable(String name, Object value, Token token);</pre>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="variableoverloading"></a>10.4.1.&nbsp;Variables overloading</h3></div>
            </div>
            <div></div>
        </div>
        <p>Variable overloading means that each path of execution can have its
            own copy of a variable with the same name. They are treated as independant
            and hence can be of different types. Variable overloading can be
            interesting if you launch multiple concurrent paths of execution over
            the same transition. Then the only thing that distinguishes those paths
            of executions are their respective set of variables.</p></div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="variableoverriding"></a>10.4.2.&nbsp;Variables overriding</h3></div>
            </div>
            <div></div>
        </div>
        <p>Variable overriding means that variables of nested paths of execution
            override variables in more global paths of execution. Generally, nested paths
            of execution relate to concurrency : the paths of execution between a fork and
            a join are children (nested) of the path of execution that arrived in the
            fork. For example, if you have a variable 'contact' in the process instance
            scope, you can override this variable in the nested paths of execution 'shipping'
            and 'billing'.</p></div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="taskinstancevariablescope"></a>10.4.3.&nbsp;Task instance variable scope
                </h3></div>
            </div>
            <div></div>
        </div>
        <p>For more info on task instance variables, see <a href="taskmanagement.html#taskinstancevariables"
                                                            title="11.4.&nbsp;Task instance variables">Section&nbsp;11.4,
            &#8220;Task instance variables&#8221;</a>.
        </p></div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="transientvariables"></a>10.5.&nbsp;临时变量
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>When a process instance is persisted in the database, normal variables
        are also persisted as part of the process instance. In some situations
        you might want to use a variable in a delegation class, but you don't want
        to store it in the database. An example could be a database connection that
        you want to pass from outside of jBPM to a delegation class. This can be
        done with transient variables.
    </p>

    <p>The lifetime of transient variables is the same as the ProcessInstance
        java object.</p>

    <p>Because of their nature, transient variables are not related to a token.
        So there is only one map of transient variables for a process instance object.</p>

    <p>The transient variables are accessable with their own set of methods
        in the context instance, and don't need to be declared in the
        processdefinition.xml</p><pre class="programlisting">Object ContextInstance.getTransientVariable(String name);
void ContextInstance.setTransientVariable(String name, Object value);</pre>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="customizingvariablepersistence"></a>10.6.&nbsp;定制变量的持久化</h2></div>
        </div>
        <div></div>
    </div>
    <p>Variables are stored in the database in a 2-step approach :</p>
    <pre class="programlisting">user-java-object &lt;---&gt; converter &lt;---&gt; variable instance</pre>
    <p>Variables are stored in <tt class="literal">VariableInstance</tt>s.
        The members of <tt class="literal">VariableInstance</tt>s are mapped to fields
        in the database with hibernate. In the default configuration of jBPM,
        6 types of VariableInstances are used:</p>

    <div class="itemizedlist">
        <ul type="disc">
            <li><p><tt class="literal">DateInstance</tt> (with one java.lang.Date
                field that is mapped to a <tt class="literal">Types.TIMESTAMP</tt> in the
                database)</p></li>
            <li><p><tt class="literal">DoubleInstance</tt> (with one java.lang.Double
                field that is mapped to a <tt class="literal">Types.DOUBLE</tt> in the
                database)</p></li>
            <li><p><tt class="literal">StringInstance</tt> (with one java.lang.String
                field that is mapped to a <tt class="literal">Types.VARCHAR</tt> in the
                database)</p></li>
            <li><p><tt class="literal">LongInstance</tt> (with one java.lang.Long
                field that is mapped to a <tt class="literal">Types.BIGINT</tt> in the
                database)</p></li>
            <li><p><tt class="literal">HibernateLongInstance</tt> (this is used for
                hibernatable types with a long id field. One java.lang.Object field is mapped
                as a reference to a hibernate entity in the database)</p></li>
            <li><p><tt class="literal">HibernateStringInstance</tt> (this is used for
                hibernatable types with a string id field. One java.lang.Object field is mapped
                as a reference to a hibernate entity in the database)</p></li>
        </ul>
    </div>
    <p><tt class="literal">Converter</tt>s convert between java-user-objects
        and the java objects that can be stored by the
        <tt class="literal">VariableInstance</tt>s. So when a process variable is set
        with e.g. <tt class="literal">ContextInstance.setVariable(String variableName, Object value)</tt>,
        the value will optionally be converted with a converter. Then the converted
        object will be stored in a <tt class="literal">VariableInstance</tt>.
        <tt class="literal">Converter</tt>s are implementations of the following
        interface: </p><pre class="programlisting">public interface Converter extends Serializable {
  boolean supports(Object value);
  Object convert(Object o);
  Object revert(Object o);
}</pre>
    <p>Converters are optional. Converters must be available to
        <a href="jpdl.html#thejbpmclassloader" title="16.2.1.&nbsp;The jBPM class loader">the jBPM class loader</a></p>

    <p>The way that user-java-objects are converted and stored in
        variable instances is configured in the file
        <tt class="literal">org/jbpm/context/exe/jbpm.varmapping.properties</tt>.
        To customize this property file, put a modified version in the root of
        the classpath, as explained in <a href="configuration.html#configurationfiles"
                                          title="6.2.&nbsp;Configuration files">Section&nbsp;6.2, &#8220;Configuration
        files&#8221;</a>
        Each line of the properties file specifies 2 or 3 class-names separated by spaces :
        the classname of the user-java-object, optionally the classname of the converter
        and the classname of the variable instance. When you refer your custom converters,
        make sure they are in <a href="jpdl.html#thejbpmclassloader" title="16.2.1.&nbsp;The jBPM class loader">the jBPM
        class path</a>.
        When you refer to your custom variable instances, they also have to be in
        the <a href="jpdl.html#thejbpmclassloader" title="16.2.1.&nbsp;The jBPM class loader">the jBPM class path</a>
        and the hibernate
        mapping file for <tt class="literal">org/jbpm/context/exe/VariableInstance.hbm.xml</tt>
        has to be updated to include the custom subclass of VariableInstance.
    </p>

    <p>For example, take a look at the following xml snippet in the file
        <tt class="literal">org/jbpm/context/exe/jbpm.varmapping.xml</tt>.</p><pre class="programlisting">    &lt;jbpm-type&gt;
      &lt;matcher&gt;
        &lt;bean class="org.jbpm.context.exe.matcher.ClassNameMatcher"&gt;
          &lt;field name="className"&gt;&lt;string value="java.lang.Boolean" /&gt;&lt;/field&gt;
        &lt;/bean&gt;
      &lt;/matcher&gt;
      &lt;converter class="org.jbpm.context.exe.converter.BooleanToStringConverter" /&gt;
      &lt;variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" /&gt;
    &lt;/jbpm-type&gt;</pre>
    <p>This snippet specifies that all objects of type <tt class="literal">java.lang.Boolean</tt> have
        to be converted with the converter <tt class="literal">BooleanToStringConverter</tt> and
        that the resulting object (a String) will be stored in a variable instance object
        of type StringInstance.</p>

    <p>If no converter is specified as in</p><pre class="programlisting">    &lt;jbpm-type&gt;
      &lt;matcher&gt;
        &lt;bean class="org.jbpm.context.exe.matcher.ClassNameMatcher"&gt;
          &lt;field name="className"&gt;&lt;string value="java.lang.Long" /&gt;&lt;/field&gt;
        &lt;/bean&gt;
      &lt;/matcher&gt;
      &lt;variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" /&gt;
    &lt;/jbpm-type&gt;</pre>
    <p>that means that the Long objects that are put in the variables are just stored
        in a variable instance of type LongInstance without being converted.</p></div>
</div>
<div class="navfooter">
    <hr>
    <table width="100%" summary="Navigation footer">
        <tr>
            <td width="40%" align="left"><a accesskey="p" href="processmodelling.html">Prev</a>&nbsp;</td>
            <td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td>
            <td width="40%" align="right">&nbsp;<a accesskey="n" href="taskmanagement.html">Next</a></td>
        </tr>
        <tr>
            <td width="40%" align="left" valign="top">Chapter&nbsp;9.&nbsp;Process Modelling&nbsp;</td>
            <td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
            <td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;11.&nbsp;Task management</td>
        </tr>
    </table>
</div>
</body>
</html>